//
// Created by 67678 on 2023/3/10.
//

#include "socketServer.h"
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <optional>
#include <memory>
#include "log.h"
#include "epoll.h"
#include "socketUtil.h"
using namespace std;
using namespace event;
using namespace socket_epoll;

SocketServer::SocketServer() {
    log("socketServer start running!");
}

SocketServer::~SocketServer() {
    log("socketServer end running!");
    if (socket_ != -1) ::shutdown(socket_, SHUT_RDWR);
}

void SocketServer::init() {
    log("socketServer initiating!");

    socket_ = socket(PF_INET, SOCK_STREAM, 0);
    if (socket_ == -1) throw runtime_error("socket create failed!");
    setNonblocking(socket_);
    int on = 1;
    int err = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    if (err == -1) throw runtime_error("socket settings failed!");

    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = IP;

    err = bind(socket_, reinterpret_cast<sockaddr *>(&addr), sizeof(addr));
    if (err == -1) throw runtime_error("socket bind failed!");

    listen(socket_, MAX_CONNECTION_NUMS);

    err = Epoll::getInstance().add(socket_, static_cast<int>(Epoll::EVENT_TYPE::IN | Epoll::EVENT_TYPE::ET));
    if (err == -1) throw runtime_error("epoll added failed!");

}

vector<shared_ptr<Event>> SocketServer::getEvents() {
    static Epoll &epoll = Epoll::getInstance();
    static auto &events = epoll.get_events();
    int num = epoll.wait();
    if (num < 0) return {};
    vector<shared_ptr<Event>> ret;
    ret.reserve(num);
    for (int i = 0; i < num; ++i) {
        using
        enum Epoll::EVENT_TYPE;
        if (events[i].events & IN) {
            if (events[i].data.fd == socket_)
                ret.emplace_back(SocketEvent::make_event(events[i].data.fd, SocketEvent::ACCEPT));
            else
                ret.emplace_back(SocketEvent::make_event(events[i].data.fd, SocketEvent::READ));
        }
        if (events[i].events & OUT)
            ret.emplace_back(SocketEvent::make_event(events[i].data.fd, SocketEvent::WRITE));

        if (events[i].events & ERR)
            ret.emplace_back(SocketEvent::make_event(events[i].data.fd, SocketEvent::ERROR));

        if (events[i].events & HUP)
            ret.emplace_back(SocketEvent::make_event(events[i].data.fd, SocketEvent::CLOSE));

    }
    return std::move(ret);
}

optional<SocketClient> SocketServer::accept() {
    sockaddr_in client_addr;
    memset(&client_addr, 0, sizeof(client_addr));
    socklen_t client_sock_len = sizeof(client_addr);
    int fd = ::accept(socket_, reinterpret_cast<sockaddr *>(&client_addr), &client_sock_len);

    if (fd == -1) return nullopt;
    SocketClient s;
    s.init(fd);
    return s;
}


